export default class ShaderConst {
    public static macrosConfig = {
        clapMacros: `#define USE_ClapProject`, //启用压平分析
        flylineMacros: '#define USE_Flyline', //启用飞行线
        exlcudeTextureProjectMafros: '#define USE_Exclude_TextureProject', //启用排除纹理投影
        floorRangeMacros: '#define USE_FloorRange', //启用建筑楼层分层的功能
        contourLine: '#define USE_ContourLine', //启用等高线分析
    };

    public static vertexPointToWorld = { //在顶点着手器中，把顶点转换到世界空间
        priority: 0,
        headerCode: `
            varying vec3 worldPositionVarying;
        `,
        contentCode: `
        vec4 objectPosition = modelMatrix * vec4(position, 1.0);
        worldPositionVarying = vec3(objectPosition); //把顶点转换到世界空间


        // vec3 objectPosition_viewSpace = vec3(objectPosition) - cameraPosition;

        // mat4 viewMatrix_viewSpace = viewMatrix;
        // viewMatrix_viewSpace[3][0] = 0.0;
        // viewMatrix_viewSpace[3][1] = 0.0;
        // viewMatrix_viewSpace[3][2] = 0.0;

        // vec4 projectPosition_viewSpace = projectionMatrix * viewMatrix_viewSpace * vec4(objectPosition_viewSpace, 1.0);
        // gl_Position = projectPosition_viewSpace;
        `
    };

    public static fragmentPointToWorld = { //在片段着手器中，把顶点转换到世界空间
        priority: 0,
        headerCode: `
            varying vec3 worldPositionVarying;
        `,
    };

    public static vertexWithinFrustum = { //在顶点着手器中，可视域分析需要用到的代码
        priority: 10,
        headerCode: `
            uniform mat4 viewMatrix_ViewField;
            uniform mat4 projectMatrix_ViewField;
            varying vec3 relationPositionVarying_ViewField;
        `,
        contentCode: `
            float relationCenterX = viewMatrix_ViewField[3][0];
            float relationCenterY = viewMatrix_ViewField[3][1];
            float relationCenterZ = viewMatrix_ViewField[3][2];
            vec3 tempCameraPosition = vec3(relationCenterX, relationCenterY, relationCenterZ);
            relationPositionVarying_ViewField = vec3(objectPosition) - tempCameraPosition;
        `
    }

    public static fragmentWithinFrustum = { //在片段着手器中，可视域分析需要用到的代码
        priority: 1,
        headerCode: `
            uniform bool isOpenViewField;
            uniform vec4 frustumPlanes[6];
            uniform int frustumPlaneCount;
            uniform vec3 viewFieldColor;
            uniform vec3 shadowColor_ViewField;
            uniform sampler2D viewFieldDepthTexture;
            uniform bool isCoverShadow_ViewField; //是否开启阴影遮挡

            uniform mat4 viewMatrix_ViewField;
            uniform mat4 projectMatrix_ViewField;
            varying vec3 relationPositionVarying_ViewField;

            bool isInFrustum(vec3 worldPosition){
                bool isInViewArea = true;

                for(int i=0; i<frustumPlaneCount; i++){
                    vec4 plane = frustumPlanes[i];
                    vec3 normal = vec3(plane.x, plane.y, plane.z);
                    float distance = plane.w;

                    if(dot(worldPosition, normal) + distance < 0.0){
                        return false;
                    }
                }
                return isInViewArea;
            }
            
            bool isInShadow(vec4 normalizePosition, sampler2D depthTexture){
                // 加上1后再除以2, 得到正确的纹理坐标
                vec2 texCoord = (normalizePosition.xy + 1.0) / 2.0;
                float currentDepth = (normalizePosition.z + 1.0) / 2.0;
                float shadowDepth = texture(depthTexture, texCoord).x;
                float accuracyError = length(vec3(normalizePosition)) / 100.0; //length(vec3(normalizePosition)) / 100.0; //0.005; //currentDepth/50.0; //这个分子参数通过外部传递进来
                bool isInShadow = (currentDepth >= shadowDepth + accuracyError) ? true : false; //计算当前pixel是否被遮挡;
                return isInShadow;
            }
            `,
        contentCode: `
            vec4 relationPosition_ViewField = vec4(relationPositionVarying_ViewField, 1.0);
            mat4 localViewMatrix_ViewField = viewMatrix_ViewField;
            localViewMatrix_ViewField[3][0] = 0.0;
            localViewMatrix_ViewField[3][1] = 0.0;
            localViewMatrix_ViewField[3][2] = 0.0;
            localViewMatrix_ViewField = inverse(localViewMatrix_ViewField);

            vec4 porjectPosition_ViewField = projectMatrix_ViewField * localViewMatrix_ViewField * relationPosition_ViewField; //投影之后的坐标点
            vec4 normalizePosition_ViewField = porjectPosition_ViewField / porjectPosition_ViewField.w; //归一化之后的坐标点

            if(isOpenViewField){ // && isInFrustum(worldPositionVarying)
                float edge = 0.95;
                if(abs(normalizePosition_ViewField.x) <= edge && abs(normalizePosition_ViewField.y) <= edge && abs(normalizePosition_ViewField.z) <= edge){
                    
                    vec4 diffuse = vec4(diffuseColor.r, diffuseColor.g, diffuseColor.b, 1.0);
                    float mixWeight = 1.0;
                    if(isCoverShadow_ViewField){ //开启阴影遮挡
                        if(isInShadow(normalizePosition_ViewField, viewFieldDepthTexture) == false){
                            diffuseColor = mix(diffuse, vec4(viewFieldColor, 1.0), mixWeight);
                        }else{
                            diffuseColor = mix(diffuse, vec4(shadowColor_ViewField, 1.0), mixWeight);
                        }
                    }else{
                        diffuseColor = mix(diffuse, vec4(viewFieldColor, 1.0), mixWeight);
                    }
                }
            }
            
            `,
        insertPlaceBefore: '#include <map_fragment>',
    };

    public static getFragmentWithinPolygon(polygonPointNum: number) {
        return {
            priority: 1,
            headerCode: `
            bool isInPolygon(vec3 point, float pointArray[${polygonPointNum * 2}], int pointCount){ 
                bool isFirst = true;
                vec3 lastNormal = vec3(0.0, 0.0, 0.0);
            
                bool isContain = true;
                for(int i=0; i<pointCount; i++){ 
                    vec3 currentPoint = vec3( vec4(pointArray[i * 2], pointArray[i * 2 + 1], 0.0, 1.0) );
                    vec3 nextPoint;
                    if(i == pointCount - 1){
                        nextPoint = vec3( vec4(pointArray[0], pointArray[1], 0.0, 1.0) );
                    }else{
                        nextPoint = vec3( vec4(pointArray[(i+1) * 2], pointArray[(i+1) * 2 + 1], 0.0, 1.0) );
                    }
                    
                    vec3 currentToNextVec = vec3(nextPoint.x-currentPoint.x, nextPoint.y-currentPoint.y, 0.0);
                    if(length(currentToNextVec) <= 0.1){
                        continue;
                    }
                    vec3 pointToCurrentVec = vec3(point.x-currentPoint.x, point.y-currentPoint.y, 0.0);
                    vec3 normal = cross(currentToNextVec, pointToCurrentVec);
                    
                    if(isFirst == true){
                    isFirst = false;
                    }else{
                        float dirct = lastNormal.z * normal.z;
                        if(dirct < 0.0) {
                            isContain = false;
                            break;
                        }
                    }
                    lastNormal = vec3(normal.x, normal.y, normal.z);
                }
                
                return isContain;
            }
            `
        };
    }

    public static getFragmentCut(polygonPointNum: number) {
        return { //在片段着手器中, 把指定区域裁剪掉
            priority: 2,
            headerCode: `
            uniform bool isOpenCut;
            uniform float cutPointArray[${polygonPointNum * 2}]; // 用于压平分析的数组
            uniform int cutPointCount; // 压平分析数组的长度`,
            contentCode: `
            vec3 positionForClap = vec3(worldPositionVarying.x, worldPositionVarying.y, 0.0);
            int pointSizeForCut = cutPointCount/2;
            if(isOpenCut && cutPointCount > 2 &&  isInPolygon(positionForClap, cutPointArray, pointSizeForCut)){
                discard; 
            }`
        };
    }

    public static getFragmentBloom(polygonPointNum) {
        return {  //在片段着手器中的淹没分析代码
            priority: 2,
            headerCode: `
            uniform bool isOpenBloom;
            uniform float bloomPointArray[${polygonPointNum * 2}]; // 用于淹没分析的数组
            uniform int bloomPointCount; // 淹没分析数组的长度 
            uniform float bloomHeight;`,
            contentCode: `
            vec3 positionForBloom = vec3(worldPositionVarying.x, worldPositionVarying.y, 0.0);
            int pointSizeForBloom = bloomPointCount / 2;
            if(isOpenBloom && worldPositionVarying.z < bloomHeight && bloomPointCount > 2 && isInPolygon(positionForBloom, bloomPointArray, pointSizeForBloom)){
                float smoothValue = 1.5 - smoothstep(0.0, bloomHeight, worldPositionVarying.z);
                vec4 waterColor = vec4(0.0, 0.0, 0.9, 1.0);
                gl_FragColor = mix(gl_FragColor, waterColor, smoothValue);       
            }`
        };
    }

    public static fragmentClapProject = { //在片段着手器中的压平区域平面mesh的代码
        priority: 3,
        headerCode: `
            #ifdef USE_ClapProject
                uniform bool isOpenClapProject;
                uniform mat4 clapProjectMatrix;
            #endif
        `,
        contentCode: `
            #ifdef USE_ClapProject
                if(isOpenClapProject){
                    mat4 mvpMatrix = clapProjectMatrix;
                    vec4 originPosition = vec4(worldPositionVarying, 1.0);
                    vec4 reflectPosition = mvpMatrix * originPosition;
                    // 加上1后再除以2, 得到正确的纹理坐标
                    vec2 texCoord = (reflectPosition.xy / reflectPosition.w + 1.0) / 2.0;
                    gl_FragColor = linearToOutputTexel(texture2D(map, texCoord)); //texture2D(map, texCoord); 
                }
            #endif
        `
    };

    public static vertexFlyline = {  //在顶点着手器中的飞线代码
        priority: 2,
        headerCode: `
        #ifdef USE_Flyline
            attribute float percent;
        #endif`,
        contentCode: `
        #ifdef USE_Flyline
            gl_PointSize = percent * size;
        #endif
        `
    };

    public static fragmenetFlyline = {   //在片段着手器中的飞线代码
        priority: 2,
        contentCode: `
        #ifdef USE_Flyline
            #ifdef OPAQUE
            diffuseColor.a = 1.0;
            #endif

            #ifdef USE_TRANSMISSION
            diffuseColor.a *= transmissionAlpha + 0.1;
            #endif
            // 设置透明度变化
            float r = distance(gl_PointCoord, vec2(0.5, 0.5));
            // diffuseColor.a = diffuseColor.a*(1.0 - r/0.5);//透明度线性变化
            diffuseColor.a = diffuseColor.a*pow( 1.0 - r/0.5, 6.0 );//透明度非线性变化  参数2越大，gl_PointSize要更大，可以直接设置着色器代码，可以设置材质size属性
            gl_FragColor = vec4( outgoingLight, diffuseColor.a );
        #endif
        `
    };

    public static vertexTextureProject = { //在顶点着手器中纹理投影的代码
        priority: 10,
        headerCode: `
            #ifndef USE_Exclude_TextureProject
                uniform mat4 virturalViewMatrix;
                uniform mat4 virturalProjectMatrix;
                varying vec3 relationPositionVarying;
            #endif
        `,
        contentCode: `
            #ifndef USE_Exclude_TextureProject
                float relationCenterPositionX = virturalViewMatrix[3][0];
                float relationCenterPositionY = virturalViewMatrix[3][1];
                float relationCenterPositionZ = virturalViewMatrix[3][2];
                vec3 virturalCameraPosition = vec3(relationCenterPositionX, relationCenterPositionY, relationCenterPositionZ);
                relationPositionVarying = vec3(objectPosition) - virturalCameraPosition;
            #endif
        `
    };

    public static fragmentTextureProject = { //在片段着手器中纹理投影的代码
        priority: 10,
        headerCode: `
            #ifndef USE_Exclude_TextureProject
                uniform bool isOpenTextureProject;
                uniform bool isCloned; //这是被克隆的对象中的像素, 用于解决一个mesh被多个视频投影的问题

                uniform mat4 virturalViewMatrix;
                uniform mat4 virturalProjectMatrix;
                varying vec3 relationPositionVarying;

                uniform sampler2D depthTexture; 
                uniform sampler2D projectTexture; //用于投影的纹理
                uniform float textureProjectMix;

                uniform bool isOpenDistortion;
                uniform float distortionStep;
                uniform float distortionAngle;

                uniform bool isOpenProjectMask;
                uniform sampler2D projectMaskTexture; //用于遮罩的纹理

                uniform bool isCoverShadow; //是否开启阴影遮挡功能
            #endif
        `,
        contentCode: `
            #ifndef USE_Exclude_TextureProject
                if(isOpenTextureProject){
                    vec4 relationPosition = vec4(relationPositionVarying, 1.0);
                    mat4 virturalLocalViewMatrix = virturalViewMatrix;
                    virturalLocalViewMatrix[3][0] = 0.0;
                    virturalLocalViewMatrix[3][1] = 0.0;
                    virturalLocalViewMatrix[3][2] = 0.0;
                    virturalLocalViewMatrix = inverse(virturalLocalViewMatrix);

                    vec4 porjectPosition = virturalProjectMatrix * virturalLocalViewMatrix * relationPosition; //投影之后的坐标点
                    vec4 normalizePosition = porjectPosition / porjectPosition.w; //归一化之后的坐标点

                    //在虚拟相机可视范围内做投影
                    if(abs(normalizePosition.x) <= 1.0 && abs(normalizePosition.y) <= 1.0 && abs(normalizePosition.z) <= 1.0){
                        // 加上1后再除以2, 得到正确的纹理坐标
                        vec2 texCoord = (normalizePosition.xy + 1.0) / 2.0;
                        float currentDepth = (normalizePosition.z + 1.0) / 2.0;
                        float shadowDepth = texture(depthTexture, texCoord).x;
                        float relativeDistance = length(relationPositionVarying) * 20.0;
                        float accuracyError = currentDepth/relativeDistance; //这个分子参数通过外部传递进来
                        bool isInShadow = false;
                        if(isCoverShadow == true){ //是否开启阴影遮挡功能
                            isInShadow = (currentDepth > shadowDepth + accuracyError) ? true : false; //计算当前pixel是否被遮挡
                        }

                        if(isInShadow == false){ //相对于投影相机没有被遮挡的部分
                            if(isOpenDistortion){ //反畸变纠正
                                vec2 newTexCoord = texCoord - vec2(0.5, 0.5);
                                float addAngle = distortionAngle;
                                float theta = atan(newTexCoord.y, newTexCoord.x) + (addAngle * (PI / 180.0));
                                float addRadius = distortionStep;
                                texCoord.x = texCoord.x + (addRadius * cos(theta));
                                texCoord.y = texCoord.y + (addRadius * sin(theta));
                            }

                            bool isShowProjectTexture = true;
                            if(isOpenProjectMask){  //遮罩
                                float maskAlpha = texture2D(projectMaskTexture, texCoord).a;
                                if(maskAlpha > 0.5){//遮罩透明度大于0.5,不显示投影纹理 
                                    isShowProjectTexture = true;
                                    // gl_FragColor = texture2D(projectMaskTexture, texCoord);
                                }else{ //遮罩透明度小于0.5,显示投影纹理
                                    isShowProjectTexture = false;
                                }
                            }
                            
                            if(isShowProjectTexture){
                                gl_FragColor = mix(gl_FragColor, texture2D(projectTexture, texCoord), textureProjectMix);
                            }
                        }
                        if(isCloned == true){
                            gl_FragColor.a = 1.0;
                        }
                       
                    }
                   
                }
            #endif
        `
    };

    public static getFragmentFloorDivision(floorRangeCount: number) { //楼层分层的shader代码
        return {
            priority: 1,
            headerCode: `
            #ifdef USE_FloorRange
               uniform vec2 floorRangeArray[${floorRangeCount}];
               uniform vec3 floorColorArray[${floorRangeCount}];
               uniform bool isOpenFloorDivision;
            #endif
            `,
            contentCode: `
            #ifdef USE_FloorRange
               if(isOpenFloorDivision){
                    float floorHeight = 3.0; //每个楼层的高度
                    for(int i = 0; i < ${floorRangeCount}; i++){
                        vec2 curFloorRange = floorRangeArray[i];
                        float startHeight = curFloorRange.x * floorHeight - floorHeight;
                        float endHeight = curFloorRange.y * floorHeight;
                        if(worldPositionVarying.z > startHeight && worldPositionVarying.z < endHeight){
                            diffuseColor.r = floorColorArray[i].r;
                            diffuseColor.g = floorColorArray[i].g;
                            diffuseColor.b = floorColorArray[i].b;
                            break;
                        }
                    }
                    
               }
            #endif
            `,
            insertPlaceBefore: '#include <map_fragment>',
        };
    }

    public static fragementcontourLine = { //高度线的shader代码
        priority: 1,
        headerCode: `
        #ifdef USE_ContourLine
            uniform bool isOpenContourLine;
            uniform float contourLineWidth;
            uniform vec3 contourLineColor;
            uniform float contourLineInterval;
        #endif
        `,
        contentCode: `
        #ifdef USE_ContourLine
               if(isOpenContourLine){
                   float modValue = mod(worldPositionVarying.z, contourLineInterval);
                   float dx = abs(dFdx(worldPositionVarying.z));
                   float dy = abs(dFdy(worldPositionVarying.z));

                   float slope = max(dx, dy); //斜率
                   float df = slope * contourLineWidth; //把contourLineWidth视为三角形中的底边。斜率乘以底边, 得到三角形的高
                   
                   float mixValue = 0.0;
                   if(modValue < df){
                        mixValue = 1.0;
                   }else{
                        mixValue = 0.0;
                   }
                   gl_FragColor = mix(gl_FragColor, vec4(contourLineColor, 1.0), mixValue);
                }
        #endif`
    };

    public static fragmentCircleRange = { //圆范围区间
        priority: 11,
        headerCode: `
               uniform vec3 circelCenter;
               uniform float circleRadius;
               uniform float circleBorderWidth;
               uniform vec3 circleRangeColor;
               uniform vec3 circleBorderColor;
               uniform float circleRangeMix;
               uniform bool isOpenCircleRange;
        `,
        contentCode: `
            if(isOpenCircleRange == true){
                vec3 positionForCircleRange = vec3(round(worldPositionVarying.x * 100.0)/100.0, round(worldPositionVarying.y * 100.0)/100.0, 0.0);
                vec3 positionForCircleCenter = vec3(round(circelCenter.x * 100.0)/100.0, round(circelCenter.y * 100.0)/100.0, 0.0);
                float distanceFromCenter = distance(positionForCircleCenter, positionForCircleRange);
                distanceFromCenter = round(distanceFromCenter * 100.0)/100.0;

                float epsilon = 0.0001;
                if(distanceFromCenter <= circleRadius+epsilon){
                    if(cameraPosition.z >= 6000.0){ //相机的高度高于一个阀值，显示边框和内部的颜色
                        if(distanceFromCenter <= circleRadius-circleBorderWidth+epsilon){
                            gl_FragColor = mix(gl_FragColor, vec4(circleRangeColor, 1.0), circleRangeMix); //圆形内的颜色
                        }else{
                            gl_FragColor = mix(gl_FragColor, vec4(circleBorderColor, 1.0), circleRangeMix);//圆形边框的颜色
                        }
                    }else{  //相机的高度低于一个阀值，只显示边框
                        if(distanceFromCenter >= circleRadius-circleBorderWidth+epsilon){
                            gl_FragColor = mix(gl_FragColor, vec4(circleBorderColor, 1.0), circleRangeMix); //圆形边框的颜色
                        }
                    }
                    
                }
            }
        `
    }
}